Skip to content

Cross-platform App Hardening (DexGuard-class), Enterprise-gated - #5527

Open
shai-almog wants to merge 111 commits into
masterfrom
app-hardening
Open

Cross-platform App Hardening (DexGuard-class), Enterprise-gated#5527
shai-almog wants to merge 111 commits into
masterfrom
app-hardening

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

What

Adds App Hardening — a single Enterprise-gated layer that renames classes/methods/fields, encrypts string constants, and obfuscates control flow across every port (Android, iOS/ParparVM, JavaScript, native desktop) from one bytecode transform, integrated with Crash Protection so obfuscated traces are still symbolicated.

Runs on the cloud build server; this repo carries the engine and the client surface. The matching BuildDaemon PR turns it on (entitlement gate + engine invocation + mapping upload).

Pieces

  • maven/cn1-hardening — forked-process ProGuard+ASM engine. Demux → ProGuard rename with a zq-prefixed dictionary that avoids the ParparVM NativeSymbolIndex dead-code-culler pathology → string encryption (LDC and static final ConstantValue, per-class decoder) → opaque-predicate control flow (safe platforms) → mangle-collision guard → CheckClassAdapter verify → mapping with provenance + mappingId. Android keeps R8 as its sole renamer.
  • maven/cn1-retrace — ProGuard mapping parse/chain + the ParparVM trace-string parser that on-device Throwable.getStackTrace() now mirrors, + a local retrace CLI.
  • Crash integrationrawStack/traceFormat/mappingId/hardenLevel payload fields, PiiScrubber.scrubRawStack, cause-chain capture.
  • Surface/entitlementharden.* hints, HardeningPreflight (fails local/source targets, invalid level, on-device-debug), Executor.hardenSourceJar/runBuild, read-only Hardening status API, simulator hint schema, new App-Hardening.asciidoc.
  • Prereq fixes — invalid build_key literal, BuildHintEditor grouped-Select .values lookup, security.asciidoc "obfuscates by default" overclaim, ParparVM getStackTrace() (fixes today's empty-frames iOS crash reports).

Tests

25 unit tests green across the two modules and the crash payload: full ProGuard round-trip + behaviour preservation, string round-trip + plaintext-absence, control-flow verification, mapping retrace + chaining, trace-format detection (incl. V8/SpiderMonkey JS rejection), and the pre-flight truth table. Core, plugin, and javase compile.

Follow-ups (not blocking)

Device end-to-end retrace and the "did obfuscation break the app" matrix need a real cloud build. Android R8 -applymapping/keep export, parparvm-symbols.txt native-address symbolication, daemon runtime stamping of cn1.mappingId/cn1.hardened, HardeningVerifier (Check 3), and SpotBugs-gate wiring for the new modules are noted for later.

Pairs with the BuildDaemon app-hardening PR.

🤖 Generated with Claude Code

Adds a single hardening layer that renames classes/methods/fields, encrypts
string constants and obfuscates control flow across every port (Android, iOS/
ParparVM, JavaScript, native desktop) from one bytecode transform, integrated
with Crash Protection so obfuscated stack traces are still symbolicated.

Engine (new maven/cn1-hardening, run as a forked process so it is single-sourced
with the build daemon and carries its own ProGuard/ASM): demux the fat jar,
rename with ProGuard using a prefixed dictionary that avoids the ParparVM
NativeSymbolIndex culler pathology, encrypt LDC literals and static-final
ConstantValue strings with a per-class decoder, opaque-predicate control flow on
safe platforms, ParparVM mangle-collision guard, CheckClassAdapter verification,
and a cross-platform mapping. Android keeps R8 as its sole renamer.

Symbolication (new maven/cn1-retrace): ProGuard mapping parse/chain plus the
ParparVM trace-string parser that java.lang.Throwable.getStackTrace() now mirrors
on device, and a local retrace CLI. Crash payload gains rawStack/traceFormat/
mappingId/hardenLevel; PiiScrubber.scrubRawStack; cause-chain capture.

Surface/entitlement: harden.* build hints, HardeningPreflight (fail the build on
local/source targets, invalid level, on-device-debug), Executor.hardenSourceJar/
runBuild wiring, a read-only Hardening status API, and the App-Hardening developer
guide chapter. Also fixes the invalid build_key literal, the BuildHintEditor
grouped-Select values lookup, and the "obfuscates by default" overclaim in the
security chapter.

Tests: 25 unit tests across the two modules and the crash payload (full ProGuard
round-trip, string round-trip + plaintext-absence, control-flow verification,
mapping retrace, trace-format detection, pre-flight truth table).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 6, 2026 10:48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae40837827

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/Executor.java Outdated
Comment thread maven/codenameone-maven-plugin/pom.xml Outdated
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces an Enterprise-gated, cross-platform “App Hardening” pipeline (bytecode-level renaming + string encryption + optional control-flow obfuscation) and integrates it with Crash Protection so hardened builds can still be symbolicated using a retained mapping.

Changes:

  • Adds new Maven modules: cn1-hardening (engine) and cn1-retrace (mapping/trace parsing + retrace CLI).
  • Integrates hardening into the Maven plugin build flow (preflight checks + engine invocation + platform IDs), and updates Crash Protection payload schema to include rawStack/traceFormat/mappingId/hardenLevel.
  • Improves ParparVM Throwable.getStackTrace() by parsing the native stack string into structured frames.

Reviewed changes

Copilot reviewed 54 out of 55 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
vm/JavaAPI/src/java/lang/Throwable.java Parse ParparVM stack text into StackTraceElements
tests/core/test/com/codename1/crash/CrashReportPayloadTest.java Tests for traceFormat + hardening fields JSON
Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults.java Adds hardening build-hint schema defaults
Ports/JavaSE/src/com/codename1/impl/javase/BuildHintEditor.java Fix grouped Select .values resolution
maven/pom.xml Adds hardening/retrace modules; bumps ProGuard
maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/HardeningPreflightTest.java Unit tests for hardening preflight matrix
maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/HardeningPreflight.java Client-side preflight validation logic
maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CN1BuildMojo.java Invoke preflight; route local builds via runBuild
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/WindowsNativeBuilder.java Provides hardening platform id
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/LinuxNativeBuilder.java Provides hardening platform id
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/JavaScriptBuilder.java Provides hardening platform id
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/IPhoneBuilder.java Provides hardening platform id
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/Executor.java Fork/execute hardening engine; mappingId/buildKey handling
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java Android: disable engine renaming; mappingId + encoded build_key
maven/codenameone-maven-plugin/pom.xml Embeds shaded hardening jar into plugin resources
maven/cn1-retrace/src/test/java/com/codename1/retrace/ParparVmTraceParserTest.java Golden tests for ParparVM trace parser
maven/cn1-retrace/src/test/java/com/codename1/retrace/MappingFileTest.java Tests for mapping parse + retrace + chaining
maven/cn1-retrace/src/main/java/com/codename1/retrace/RetraceMain.java Standalone retrace CLI entrypoint
maven/cn1-retrace/src/main/java/com/codename1/retrace/ParparVmTraceParser.java Parses ParparVM text traces; rejects JS stacks
maven/cn1-retrace/src/main/java/com/codename1/retrace/MappingFile.java Parses/inverts ProGuard mapping for retrace
maven/cn1-retrace/src/main/java/com/codename1/retrace/MappingChain.java Applies multiple mappings in order
maven/cn1-retrace/src/main/java/com/codename1/retrace/Frame.java Frame DTO for retrace pipeline
maven/cn1-retrace/pom.xml Module build + shaded standalone jar
maven/cn1-hardening/src/test/java/com/codename1/hardening/StringEncryptTransformTest.java End-to-end string encryption tests
maven/cn1-hardening/src/test/java/com/codename1/hardening/fixture/Secrets.java Fixture class for encryption tests
maven/cn1-hardening/src/test/java/com/codename1/hardening/fixture/Helper.java Fixture class for rename tests
maven/cn1-hardening/src/test/java/com/codename1/hardening/ControlFlowTransformTest.java Control-flow guard verification tests
maven/cn1-hardening/src/main/java/com/codename1/hardening/StringEncryptTransform.java ASM transform: encrypt LDC + ConstantValue strings
maven/cn1-hardening/src/main/java/com/codename1/hardening/ProGuardRunner.java Programmatic ProGuard rename runner
maven/cn1-hardening/src/main/java/com/codename1/hardening/OutputVerifier.java CheckClassAdapter verification gate
maven/cn1-hardening/src/main/java/com/codename1/hardening/MappingWriter.java Mapping header + mappingId computation
maven/cn1-hardening/src/main/java/com/codename1/hardening/MangleCollisionCheck.java Guards ParparVM symbol mangle collisions
maven/cn1-hardening/src/main/java/com/codename1/hardening/Main.java Engine CLI front-end + exit codes
maven/cn1-hardening/src/main/java/com/codename1/hardening/JarDemuxer.java Split/rebuild fat jar around class entries
maven/cn1-hardening/src/main/java/com/codename1/hardening/InputJarKeepScanner.java ASM scan for reflective keep rules
maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningResult.java Engine result model
maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningRequest.java Engine request model
maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningProfile.java Hardening levels + defaults
maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningException.java Engine exception type
maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningEngine.java Pipeline orchestration + safety gates
maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningConfig.java Parses harden.* hints into config
maven/cn1-hardening/src/main/java/com/codename1/hardening/ControlFlowTransform.java ASM opaque-predicate entry guards
maven/cn1-hardening/src/main/java/com/codename1/hardening/Cn1NameFactory.java zq-prefixed dictionary generator
maven/cn1-hardening/src/main/java/com/codename1/hardening/BuiltinKeepRules.java Tier-1 keep rules + shared R8 rules
maven/cn1-hardening/pom.xml Engine module deps + shaded standalone jar
docs/developer-guide/security.asciidoc Correct obfuscation claims; reference hardening
docs/developer-guide/developer-guide.asciidoc Include App-Hardening chapter
docs/developer-guide/Crash-Protection.asciidoc Document new crash payload fields + hardening flow
docs/developer-guide/App-Hardening.asciidoc New hardening chapter
CodenameOne/src/com/codename1/security/hardening/package-info.java Package docs for Hardening API
CodenameOne/src/com/codename1/security/hardening/Hardening.java Read-only hardening status API
CodenameOne/src/com/codename1/crash/PiiScrubber.java Add scrubRawStack hook
CodenameOne/src/com/codename1/crash/CrashReportPayload.java Add rawStack/traceFormat/mappingId/hardenLevel
CodenameOne/src/com/codename1/crash/CrashProtection.java Capture/scrub rawStack; include in payload
Suppressed comments (2)

maven/cn1-hardening/src/main/java/com/codename1/hardening/HardeningConfig.java:99

  • Any unrecognized harden.strings value currently falls into the final else branch and enables maximum string encryption. This can turn on expensive/behaviour-changing encryption accidentally (e.g. a typo), so the parser should only treat explicit "all"/"true"/"2"/"3" as 'all' and otherwise fall back to the level defaults (or fail).
            } else {
                // "all", "true", "2", "3"
                encConst = true;
                encAll = true;
            }

docs/developer-guide/Crash-Protection.asciidoc:93

  • This paragraph states that on ParparVM ports the Java trace arrives only as rawStack and is parsed server-side. With Throwable.getStackTrace() now parsing the ParparVM stack string into structured frames on-device, the server may receive both; consider updating this sentence to reflect that rawStack is still parparvm-text but frames may be structured too (and rawStack may primarily be for the cause-chain / verbatim trace).
When a build is hardened (see <<app-hardening>>), the build server retains the cross-platform obfuscation mapping and symbolicates incoming reports against it, so a hardened build's crashes still land as readable, correctly-lined issues. Two things follow from how the mapping is retained: a report whose mapping has aged out of retention can no longer be retraced, and a locally hardened build -- whose mapping never reached the server -- can't be symbolicated at all. On the ParparVM ports (iOS, tvOS, watchOS, mac-native, Windows, Linux) the Java trace arrives as `rawStack` in the `parparvm-text` format and is parsed server-side; on the JavaScript port it arrives as a JavaScript engine stack (`js-error`) and is symbolicated best-effort through the source map.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/developer-guide/Crash-Protection.asciidoc Outdated
Comment thread CodenameOne/src/com/codename1/crash/CrashReportPayload.java Outdated
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 493 total, 0 failed, 54 skipped

Benchmark Results

  • Execution Time: 23907 ms

  • Hotspots (Top 20 sampled methods):

    • 16.65% java.util.ArrayList.indexOf (315 samples)
    • 5.13% com.codename1.tools.translator.ByteCodeClass.hasDeclaredMethod (97 samples)
    • 3.86% com.codename1.tools.translator.BytecodeMethod.addToConstantPool (73 samples)
    • 3.59% java.lang.StringBuilder.append (68 samples)
    • 3.38% com.codename1.tools.translator.Parser.classIndex (64 samples)
    • 2.75% com.codename1.tools.translator.BytecodeMethod.equals (52 samples)
    • 2.54% com.codename1.tools.translator.Parser.cn1EnsureSubclassIndex (48 samples)
    • 2.38% org.objectweb.asm.tree.analysis.Analyzer.analyze (45 samples)
    • 2.17% com.codename1.tools.translator.Parser.addToConstantPool (41 samples)
    • 1.96% org.objectweb.asm.tree.analysis.Analyzer.findSubroutine (37 samples)
    • 1.85% com.codename1.tools.translator.BytecodeMethod.appendCMethodPrefix (35 samples)
    • 1.80% com.codename1.tools.translator.BytecodeMethod.optimize (34 samples)
    • 1.74% java.util.HashMap.hash (33 samples)
    • 1.53% java.lang.Object.hashCode (29 samples)
    • 1.53% java.lang.String.equals (29 samples)
    • 1.43% com.codename1.tools.translator.Parser.generateClassAndMethodIndexHeader (27 samples)
    • 1.27% com.codename1.tools.translator.bytecodes.Invoke.resolveDirectTarget (24 samples)
    • 1.22% org.objectweb.asm.ClassReader.readCode (23 samples)
    • 1.11% java.util.TreeMap.getEntry (21 samples)
    • 1.06% com.codename1.tools.translator.Parser.resolveDupForms (20 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

- Complete GPLv2+Classpath header on the 4 files the copyright gate flagged
  (BuildHintEditor had none; BuildHintSchemaDefaults + the two new tests were short).
- Convert Hardening.java/package-info.java to /// markdown comments (core src gate).
- Declare cn1-hardening:standalone as a runtime-scope plugin dependency so the reactor
  builds the engine before the plugin embeds it (fixes the antrun copy failing in CI);
  fix an illegal -- inside the new XML comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 6, 2026 11:15
ProGuard 7.3.2 cannot read class files newer than JDK 20 (it fails on the JDK's
own module classes), so the renamer must run on JDK 8-20 -- the cloud daemon
forks the engine on JDK 17. The engine now fails with a clear message instead of
a cryptic ProGuard error when renaming is requested on a too-new JVM, and the
ProGuard-dependent tests skip (JUnit assumption) on JDK 21+ so the PR CI JDK-21
leg stays green. String encryption and control-flow tests have no such limit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc8822afde

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/Executor.java Outdated
Comment thread maven/cn1-hardening/src/main/java/com/codename1/hardening/BuiltinKeepRules.java Outdated
- FrameClassWriter: COMPUTE_FRAMES resolved common superclasses through the
  engine's own classloader, which lacks the app/library classes when run as a
  forked jar, so any class with a merge between application types aborted
  hardening. Resolve the hierarchy from a classloader over the (renamed) input
  classes plus the library jars, falling back to Object. Threaded through the
  string-encryption and control-flow transforms; unit-tested. (Codex P1)
- Pass the FULLY QUALIFIED main class to the keep rules: getMainClass() is the
  simple name, so a bare value kept a default-package class and let ProGuard
  rename the real application class out from under the generated stub. Fixed in
  both the plugin and daemon config writers. (Codex P1)
- The reactor dependency forcing cn1-hardening to build before the plugin (so
  the engine jar exists for the embed step) already landed in the prior commit. (Codex P1)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 57 changed files in this pull request and generated no new comments.

Suppressed comments (3)

Ports/JavaSE/src/com/codename1/impl/javase/BuildHintEditor.java:206

  • Select-hint value parsing uses the last character of the values string as the delimiter (charAt(len-1)), which breaks all of the comma-separated .values entries coming from BuildHintSchemaDefaults (e.g. off,standard,aggressive,paranoid will split on d). This prevents the new Hardening Select hints (and existing ones like nativeTheme) from populating correctly.
                            String separator = ""+valuesString.charAt(valuesString.length()-1);
                            ArrayList<String> values = new ArrayList<String>();
                            values.add("");
                            for (String value : valuesString.split(separator)) {

docs/developer-guide/Crash-Protection.asciidoc:86

  • This section says ParparVM ports rely on rawStack because getStackTrace() yields only a formatted string, but this PR updates vm/JavaAPI/java/lang/Throwable.getStackTrace() to parse the ParparVM text stack into structured StackTraceElement[]. The docs should be updated to reflect that structured frames are now available on ParparVM (and rawStack is supplemental / for the full rendered text and cause chain).
- `frames[]` -- class / method / file / line / `native` flag per frame
- `rawStack` -- the pre-rendered Java stack (via `printStackTrace`, including the cause chain). On the ParparVM ports this is the readable Java trace, since `getStackTrace()` there yields a formatted string rather than structured frames
- `traceFormat` -- how the server should read `rawStack`: `structured`, `parparvm-text`, `js-error`, or `none`. Derived, never guessed

maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/Executor.java:2457

  • The generic catch (Exception e) wraps the error without the original cause, which makes diagnosing hardening failures much harder (stack trace is lost). Preserve the cause in the BuildException.

Copilot AI review requested due to automatic review settings August 6, 2026 11:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: efa163b074

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/cn1-hardening/src/main/java/com/codename1/hardening/OutputVerifier.java Outdated
Comment thread Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults.java Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 57 changed files in this pull request and generated no new comments.

Suppressed comments (2)

vm/JavaAPI/src/java/lang/Throwable.java:144

  • setStackTrace() updates parsedStack, but printStackTrace() prints the pre-rendered "stack" string field. Because setStackTrace() doesn't update "stack", callers that set a custom stack trace will still see the old/empty stack printed (and CrashProtection.safeRawStack() relies on printStackTrace()). Rebuild the "stack" string from the provided StackTraceElement[] so printStackTrace() reflects the updated trace.
    CodenameOne/src/com/codename1/crash/CrashReportPayload.java:120
  • CrashReportPayload documents hardenLevel as one of "off"/"standard"/"aggressive"/"paranoid", but it currently defaults to the empty string when the property isn't set. This makes the payload ambiguous for unhardened builds and diverges from Hardening.getLevel() which defaults to "off".
        this.osVersion = d.getProperty("OSVer", "");
        this.mappingId = d.getProperty("cn1.mappingId", "");
        this.hardenLevel = d.getProperty("cn1.hardenLevel", "");
        Locale loc = Locale.getDefault();

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

Codex P1/P2:
- harden.keep: split on newlines only (a ';' is legal inside a rule body).
- Keep SourceFile,LineNumberTable so ParparVM/native traces keep real line
  numbers for retrace.
- Honor constants-vs-all string mode: 'constants' encrypts only values declared
  as static-final String constants (and javac's inlined copies), 'all' encrypts
  every literal.
- Propagate cn1.mappingId/cn1.hardened/cn1.hardenLevel into the request before
  stub generation; Android stub now stamps them (Hardening.isHardened(), crash
  report mappingId/level).
- Supply the compile/platform classpath to ProGuard as library jars so an app
  method overriding a framework method is not renamed apart from its superclass.
- Append harden.keep + the name-bound PropertyBusinessObject keep to Android's
  R8 config (Android keeps R8 as sole renamer).

Build fixes:
- CrashProtection.safeRawStack: build the raw stack with StringBuilder instead of
  java.io.PrintWriter, which the core's CLDC11 bootclasspath (ANT build) lacks.
- Embed the engine jar via maven-dependency-plugin:copy (resolves the standalone
  artifact from the reactor/repo) so partial plugin-only CI builds no longer fail
  copying from an unbuilt sibling target/.
- Keep the test resource bytes ASCII (explicit byte[] rather than a non-ASCII
  literal).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 6, 2026 11:52

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 605f722c41

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/crash/CrashProtection.java Outdated
…, Select delimiters)

- OutputVerifier: pass the input/library hierarchy classloader to
  CheckClassAdapter.verify so the final verification pass resolves application
  types instead of loading them from the engine's classpath (a class with a merge
  between app types would otherwise fail verification). (P1)
- Keep every class named by a META-INF/services/* descriptor (the service
  interface and each provider), since the descriptors are copied verbatim and
  ServiceLoader would break if they were renamed; regression-tested. (P1)
- Terminate the hardening Select .values lists with their delimiter, which
  BuildHintEditor reads as the last character, so the simulator shows the real
  options instead of splitting on a letter. (P2)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shai-almog

shai-almog commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 12 screenshots: 12 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0fffb4c59f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/cn1-hardening/src/main/java/com/codename1/hardening/Main.java Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 57 out of 57 changed files in this pull request and generated no new comments.

Suppressed comments (5)

maven/cn1-hardening/src/main/java/com/codename1/hardening/JarDemuxer.java:120

  • rebuild() doesn’t close its ZipOutputStream. Even with an explicit finish(), closing the stream is the reliable way to release the deflater/native resources and ensure the central directory is flushed.
        FileOutputStream fo = new FileOutputStream(outJar);
        try {
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fo));
            for (Map.Entry<String, byte[]> e : classesByInternalName.entrySet()) {
                ZipEntry entry = new ZipEntry(e.getKey() + ".class");

maven/cn1-hardening/src/main/java/com/codename1/hardening/JarDemuxer.java:145

  • readClasses() creates a ZipInputStream but never closes it. Closing only the underlying FileInputStream works most of the time, but it’s safer and clearer to close the ZIP stream explicitly (try-with-resources).
        FileInputStream fi = new FileInputStream(jar);
        try {
            ZipInputStream zis = new ZipInputStream(fi);
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {

Ports/JavaSE/src/com/codename1/impl/javase/BuildHintEditor.java:201

  • propName.indexOf("}}.") is assumed to be present here. If it isn’t (unexpected/third-party schema key), the current substring(... + 3) call will produce an incorrect key (and can throw if the key is shorter), and valuesString.charAt(valuesString.length()-1) will also throw on an empty values string. Consider guarding the index/length and making the value-splitting robust (comma-separated lists in this repo don’t end with a delimiter).
                        String valuesKey = propName.substring(0, propName.indexOf("}}.")+3) + "values";
                        String valuesString = System.getProperty(valuesKey);
                        if (valuesString == null) {
                            valuesString = System.getProperty("codename1.arg.{{ "+model.name+" }}.values");
                        }

CodenameOne/src/com/codename1/crash/CrashReportPayload.java:147

  • deriveTraceFormat() can classify a raw stack as parparvm-text even if the frame body contains spaces. That diverges from the on-device ParparVM parser logic (which rejects frames containing spaces) and could send the server down the wrong parse path for some JS engine stack formats.
        int at = rawStack.indexOf("    at ");
        if (at >= 0) {
            int lineEnd = rawStack.indexOf('\n', at);
            String body = lineEnd < 0 ? rawStack.substring(at + 7) : rawStack.substring(at + 7, lineEnd);
            if (body.indexOf('(') < 0 && body.indexOf('/') < 0 && body.indexOf('@') < 0) {

maven/cn1-hardening/src/main/java/com/codename1/hardening/JarDemuxer.java:103

  • split() creates ZipInputStream/ZipOutputStream but never closes them. Relying on only closing the underlying FileInputStream/FileOutputStream can leak native resources and (for the output) risks incomplete ZIP finalization on some JVMs/filesystems. Use try-with-resources to ensure ZIP streams are closed.

This issue also appears in the following locations of the same file:

  • line 116
  • line 141
            ZipInputStream zis = new ZipInputStream(fi);
            FileOutputStream fo = new FileOutputStream(classesJarOut);
            try {
                ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fo));
                ZipEntry entry;

Copilot AI review requested due to automatic review settings August 6, 2026 12:05
MappingWriter.jsonEscape only escaped quote and backslash, so a SourceFile
containing a newline, tab or other control character was emitted literally --
a raw newline split the single-line metadata comment and a raw control char is
invalid JSON, either of which stopped MappingFile.parseSourceFileMetadata from
recovering the filename (retrace then fell back to a synthesized path). This is
reachable for a Kotlin or package-private Java class in an unusually named Unix
file. Escape b/f/n/r/t and other control chars (as the 4-hex-digit form), and
teach the reader to decode those escapes back. Round-trip tested both sides.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 799372c730

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/cn1-retrace/src/main/java/com/codename1/retrace/MappingFile.java Outdated
parseSourceFileMetadata trim()'d the decoded fileName, so a Unix source file
whose name has leading/trailing whitespace (e.g. " Screen.kt") retraced to a
different, nonexistent filename and broke source links. The closing quote
bounds the JSON string exactly, so return the decoded value verbatim and treat
only a genuinely empty value as absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 374c2168b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

A HealthBackgroundListener is reconstructed after a process restart by its
persisted class name: HealthStore writes getClass().getName() to Preferences,
and the platform builder scans the hardened jar to generate a factory mapping
that name back to a constructor. The engine's keep set omitted it, so an
engine-renamed Apple/native build renamed the implementor; because the default
mapping seed changes between builds, an updated app's regenerated factory no
longer recognized the previously persisted name and resolveBackgroundListener()
silently returned nothing, deferring background health delivery. Keep the
implementors, exactly as the location/background-callback and Login rules do.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 364d1101ba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

shai-almog and others added 3 commits August 10, 2026 08:51
applyHardeningRequestArgs was called only from the Android/iOS/JavaScript
request builders; the Windows and Linux native builders (windows-source,
local-windows-device, local-linux-device) built their request and called
runBuild without it. So a local Windows/Linux build that took
harden.allowUnhardenedLocalBuild=true injected no cn1.harden.forceOff and
hardenSourceJar ran hardening anyway, producing an orphaned local mapping.
Call the helper from those two request builders too; all five runBuild sites
now carry the per-build decision.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Migrating a static-final String's ConstantValue into <clinit> changes
initialization ordering: the ConstantValue is otherwise assigned during
preparation, before any <clinit> runs, so a superclass whose <clinit> reads a
subclass constant during a REENTRANT initialization observes the value, whereas
a <clinit>-assigned field is still null at that reentrant point. javac and
kotlinc both inline compile-time String constant reads, so this only arises for
generated bytecode that emits a real GETSTATIC. Scan the jar for such reads and
preserve those fields' ConstantValue (plaintext, disclosed), excluding the
value jar-wide so an equal LDC elsewhere is not encrypted+interned and broken
== against it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…limit

FrameClassWriter: an interface-involving frame merge resolves to Object and is
deliberately NOT flagged incomplete even under a partly-readable interface
hierarchy -- the verifier treats every class as assignable to every loadable
interface (JVMS 4.10.1.2), so a later invokeinterface still verifies; flagging
it would only needlessly un-harden a valid class. Document the reasoning at the
early return.

JarDemuxer: resources are copied under their original path, so a package-
relative getResourceAsStream from a renamed class misses them. This is a
deliberate choice -- CN1's resource model uses absolute paths and package names
are obfuscated on purpose -- so document it (and the harden.keep escape hatch
for a bundled dependency that loads a package-relative resource) at the copy
site and in App-Hardening.asciidoc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9757e155cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/crash/CrashReportPayload.java Outdated
The App-Hardening resource-limitation note tripped Microsoft.Adverbs on
"rarely"; reword without the adverb. No content change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5fb8161ef0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/cn1-hardening/src/main/java/com/codename1/hardening/FrameClassWriter.java Outdated
shai-almog and others added 2 commits August 10, 2026 10:18
FrameClassWriter: the superclass walk returned java/lang/Object via
isAssignableFromBytes(Object, type2) -- always true -- BEFORE the
chainReachesObject incompleteness check, so a merge where type2's chain is
broken by a missing intermediate that hides a nearer common base (A extends
Base, B extends an absent Missing extends Base) was emitted as Object without
being flagged. Stop the walk before Object so reaching it falls through to the
incompleteness check; a broken type2 chain is now flagged and the class shipped
unhardened.

StringEncryptTransform: the GETSTATIC collector recorded the reference owner
(C.X), but an inherited field read (GETSTATIC C.X for a field declared by
superclass B) must key on the declaring class B.X, which is what
encryptStaticFinalStrings checks. Resolve the owner to the field's declaring
class through the hierarchy before recording it, so the ConstantValue of an
inherited, externally-read constant is preserved rather than migrated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
deriveTraceFormat labeled any non-JavaScript raw stack containing a
"    at X.Y:N" line (no parens) as parparvm-text purely by shape. An
Android/desktop (real-JVM) throwable whose MESSAGE contains such a line --
printStackTrace echoes the message into the raw stack -- was then misclassified,
letting the server fabricate a frame from message text or drop a real cause
trace. Gate the classification on an actual ParparVM-C runtime platform
(ios/mac/linux/win); a real-JVM stack now stays none regardless of message
contents. The shape check still guards an unexpected stack on a C target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1bf1604ca7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/crash/CrashReportPayload.java
JavaSEPort.getPlatformName() returns mac/win for a skinless desktop app (Linux
falls through to win), which collide with the native ParparVM-C names, so the
platform-name gate still misclassified a JavaSE desktop throwable whose message
contained a "    at X.Y:N" line as parparvm-text. ParparVM's System.getProperty
always returns null while a real JVM sets java.vm.name, so derive the trace
format from that runtime signal: anything on a JVM (JavaSE desktop, the
simulator, or Android) is never parparvm-text regardless of its displayed name.
A package-private 4-arg overload takes runningOnJvm explicitly so a JVM-hosted
unit test can still exercise the native path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4cc1541b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/cn1-hardening/src/main/java/com/codename1/hardening/OutputVerifier.java Outdated
Comment thread maven/cn1-retrace/src/main/java/com/codename1/retrace/RetraceMain.java Outdated
shai-almog and others added 2 commits August 10, 2026 11:13
OutputVerifier handled the case where CheckClassAdapter.verify THROWS on an
absent target-only type, but ASM sometimes catches that failure internally and
prints its stack trace to the report instead. A non-empty report was then
rejected, so a class whose frame analysis needs an unavailable platform
superclass could still fail hardening. Detect the unresolved-type text in the
report (ClassNotFoundException / TypeNotPresentException / NoClassDefFoundError
/ " not present") and take the structural fallback, mirroring
BytecodeComplianceMojo's isUnresolvableTypeOutput.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The standalone retrace CLI opened mapping files with FileReader (platform
default charset), corrupting Unicode class/method/source-file names on a
non-UTF-8 host such as Windows Java 8. The rest of the pipeline treats mappings
as UTF-8 (MappingWriter reads/writes UTF-8), so read them with an explicit
UTF-8 reader for consistent symbolication across hosts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4124a5e38e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/crash/PiiScrubber.java Outdated
The opening paragraph still described the old "mask only non-frame lines"
behavior and promised a minified-JS coordinate like app.js:1:123456 survives,
contradicting the accurate explanation later in the same javadoc. scrubRawStack
now routes every line through scrubMessage, so document the uniform masking and
its loss of large columns (short line numbers still survive; precise
coordinates come from structured frames). No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ffe1519a3c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread maven/cn1-hardening/src/main/java/com/codename1/hardening/OutputVerifier.java Outdated
shai-almog and others added 2 commits August 10, 2026 12:57
…cuit

The Android APK cache check (skip build when the APK is newer than the sources)
returned before applyHardeningPreflight() ran, and getSourcesModificationTime()
keys only on source timestamps -- not build hints -- so an explicit hardening
request, especially one made via a -D command-line property, was silently
dropped and the stale, potentially unhardened APK returned with no error. Move
the preflight ahead of the cache check and overlay -D command-line hints in the
early preflight so the request is seen, validated, and refused if unsupported
rather than silently ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OutputVerifier classified an entire CheckClassAdapter report as an
unresolved-type failure by substring, but ASM can append both a missing-type
diagnostic (one method) and a genuine analyzer error (another method) to the
same report; the structural fallback then discarded the real error and shippable
invalid bytecode. Verify structure once, then run SimpleVerifier data-flow
PER METHOD: a method that fails only because a target-only type is absent is
tolerated, while any other analyzer failure fails the build, naming the method.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b6485ffc1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Moving the pre-flight ahead of the cache check validated the hardening request
but did not invalidate the cache, so an off->standard change made through a -D
hint (which getSourcesModificationTime cannot see) still returned the older,
possibly unhardened APK. Record whether the pre-flight resolved that hardening
will run (non-off level and not force-off) and skip the source-timestamp cache
short-circuit in that case, forcing a rebuild so the request is honored. When
hardening is off / force-off / opted out, the cache still applies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 760804329f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The previous guard only bypassed the up-to-date cache for off->on; disabling
hardening (on->off, opting Android out, or turning every transform off) left
hardeningWillRun false, so the cache returned the old HARDENED APK -- an
artifact contradicting the current config. Record the hardening OUTCOME the APK
was built with ("unhardened" or "hardened:<level>") in a marker beside the APK,
and treat the cache as up-to-date only when that marker still matches. A change
in either direction now rebuilds, while two unhardened (or identical-level)
invocations still hit the cache.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4684e09cf5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The marker keyed only on harden.level, so changing harden.strings, harden.rename,
harden.controlFlow, harden.keep or harden.seed without changing the level left
the key identical (both aggressive builds were "hardened:aggressive") and the
timestamp cache reused an APK built with the previous transforms and mapping.
Fingerprint every effective codename1.arg.harden.* setting (sorted, SHA-256) into
the hardened key so any transform/keep/seed change invalidates the cache; an
unhardened build keeps its single key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants